package com.cloud.ebookreader;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Locale;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

import com.cloud.ebookreader.access.Book;
import com.cloud.ebookreader.access.Component;
import com.cloud.ebookreader.access.LibraryFactory;
import com.cloud.ebookreader.http.ReaderConstants;
import com.cloud.ebookreader.http.UrlQueryParameterConstants;
import com.cloud.ebookreader.javascript.JavaScriptCreator;
import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController extends AbstractController {

	private static final Logger logger = LoggerFactory
			.getLogger(HomeController.class);
	public static final String BUCKETNAME = "cloudebookreader";
	public static final String FILENAME = "mytestfile.txt";
	public static final String SAMPLE_BOOK_KEY = "sample-ebook";
	
	/**
	 * Simply selects the home view to render by returning its name.
	 * 
	 * @throws IOException
	 */
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) throws IOException {
		logger.info("Welcome home! the client locale is " + locale.toString());
		return "upload";
	}
	
	@SuppressWarnings("deprecation")
	@RequestMapping(value = "/upload", method = RequestMethod.POST)
	public String uploadEbook(HttpServletRequest req, Locale locale, Model model) throws IOException, ServletException {
		BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
		
		Map<String, BlobKey> blobs = blobstoreService.getUploadedBlobs(req);
        BlobKey blobKey = blobs.get("myFile");

        if (blobKey == null) {
            System.out.println("The upload is not success");
            model.addAttribute("success", false);
        } else {
        	System.out.println("The upload is success");
        	model.addAttribute("success", true);
        }
        return "redirect:/readbook?blob-key=" + blobKey.getKeyString();
	}
	
	@RequestMapping(value = "/readbook", method = RequestMethod.GET)
	public String sampleFile(HttpServletRequest req , HttpServletResponse res, Locale locale, Model model) throws IOException {
		String ebookBlobKey = req.getParameter("blob-key");
		Book book = null;
		
		try {
            book = getBookFromSession(req, ebookBlobKey);
        } catch (Exception error) {
        	model.addAttribute("error", error.getMessage());
        	return "error";
        }
		
        //get Javascript object
        String bookScript = JavaScriptCreator.createBookJavascript(ebookBlobKey, req.getContextPath(), book);
        model.addAttribute(ReaderConstants.REQUEST_ATTRIBUTE_BOOKSCRIPT, bookScript);
        
		return "book";
	}

	@RequestMapping(value = "/getComponent", method = RequestMethod.GET)
	public void getComponent(HttpServletRequest req, HttpServletResponse res) throws IOException {
		String ebookBlobKey = req.getParameter(UrlQueryParameterConstants.BOOK_BLOB_KEY);
		String componentId = req.getParameter(UrlQueryParameterConstants.COMPONENT_ID).toString();
		
		Book book = null;
		
		try {
			book = getBookFromSession(req, ebookBlobKey);
		}catch (Exception e) {
			returnTextMessage(res, e.getMessage());
        	return;
		}
		
		Component component = book.getComponent(componentId);
        if (component == null) {
            returnTextMessage(res, "Component not found. BlobKey: " + ebookBlobKey + " Component id: " + componentId);
        	return;
        }
        returnBinary(res, component.getContent(), component.getMime());
        return;
	}
	
	@Override
	protected ModelAndView handleRequestInternal(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		// TODO Auto-generated method stub
		return null;
	}
	
	private Book getBookFromSession(HttpServletRequest req, String ebookBlobKey) {
		Book book = null;
		//Get Book from session
		String currentBookBlobKey = (String) req.getSession().getAttribute(ReaderConstants.REQUEST_ATTRIBUTE_BOOKBLOBKEY);
        if (currentBookBlobKey != null && currentBookBlobKey.equals(ebookBlobKey)) {
        	book = ( Book ) req.getSession().getAttribute(ReaderConstants.REQUEST_ATTRIBUTE_BOOK);
        }
        //if not have book in session
        if (book == null) {
        	try {
        		book = LibraryFactory.getLibrary().getBook(ebookBlobKey);
        		req.getSession().setAttribute(ReaderConstants.REQUEST_ATTRIBUTE_BOOK, book);
        		req.getSession().setAttribute(ReaderConstants.REQUEST_ATTRIBUTE_BOOKBLOBKEY, ebookBlobKey);
        	} catch (Exception error) {
        		throw new RuntimeException("Error while loading book: " + error.getMessage());
        	}
        }
        //no book found
        if (book == null) {
            throw new RuntimeException("Book not found: ");
        }
        return book;
	}
	
	private void returnBinary(HttpServletResponse response, InputStream content, String mimeType)
            throws IOException {
		
        response.setContentType(StringUtils.isEmpty(mimeType) ? "application/octet-stream" : mimeType);
        OutputStream o = response.getOutputStream();
        try{
            IOUtils.copy(content, o);
        }finally{
            o.close();
            content.close();
        }
    }

    private void returnTextMessage(HttpServletResponse response, String msg)
            throws IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = null;
        try {
            out = response.getWriter();
            out.println(msg);
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }
}
